﻿/* ============================================================================
(c) Copyright 2012 Hewlett-Packard Development Company, L.P.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge,publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
============================================================================ */
using System;
using System.Security;
using System.Diagnostics;
using System.Net;
using System.Net.Http;

namespace HPCloud.Objects.DataAccess
{
    public static class ExceptionFactory
    {
//=================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="httpStatusCode"></param>
//=================================================================================================
        public static Exception CreateUserManagementException(HttpResponseMessage msg)
        {
            msg.Content.LoadIntoBufferAsync();
            switch (msg.StatusCode)
            {
                case (HttpStatusCode.Unauthorized):
                    return new SecurityException("The request required user authentication.");

                case (HttpStatusCode.Forbidden):
                    return new SecurityException("The service understood the request, but refused to fulfill it, authorization will not help.");

                case (HttpStatusCode.UnsupportedMediaType):
                    return new InvalidOperationException("415 Unsupported Media Type");

                default:
                    return new Exception(msg.Content.ReadAsStringAsync().Result);
            }
        }
//=================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="httpStatusCode"></param>
/// <returns></returns>
//=================================================================================================
        public static Exception CreateSecurityRepositoryException(HttpResponseMessage msg)
        {
            msg.Content.LoadIntoBufferAsync();
            switch (msg.StatusCode)
            {
                case (HttpStatusCode.NotFound):
                    return new InvalidOperationException("The resource requested does not exist.");

                case (HttpStatusCode.Forbidden):
                    {
                        if (msg.Content.ReadAsStringAsync().Result.Contains("AccessDenied"))
                        {
                            return new SecurityException(@"Access Denied. Please check the ACL\Policy settings for the requested resource. Ensure that you have the proper rights to the operation requested.");
                        }
                        else
                        {
                            return new InvalidOperationException("Signature verification has failed..");
                        }
                    }
                default:
                    return new Exception(msg.Content.ReadAsStringAsync().Result);
            }
        }
//=================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="httpStatusCode"></param>
/// <returns></returns>
//=================================================================================================
        public static Exception CreateServerRepositoryException(HttpResponseMessage msg)
        {
            msg.Content.LoadIntoBufferAsync();
            switch (msg.StatusCode)
            {
                case (HttpStatusCode.NotFound):
                    {
                        return new InvalidOperationException("The resource requested does not exist.");
                    }

                case (HttpStatusCode.BadRequest):
                    {
                        if (msg.Content.ReadAsStringAsync().Result.Contains("Cannot find requested image"))
                        {
                            return new SecurityException(@"Invalid ImageId supplied.");
                        }
                        else if (msg.Content.ReadAsStringAsync().Result.Contains("Cannot find requested flavor"))
                        {
                            return new SecurityException(@"Invalid FlavorId supplied.");
                        }
                    }
                    break;

                default:
                    return new Exception(msg.Content.ReadAsStringAsync().Result);
            }

            return new Exception(msg.Content.ReadAsStringAsync().Result);
        }
//=================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="httpStatusCode"></param>
/// <returns></returns>
//=================================================================================================
        public static Exception CreateStorageObjectRepositoryException(HttpResponseMessage msg)
        {
            msg.Content.LoadIntoBufferAsync();
            switch (msg.StatusCode)
            {
                case (HttpStatusCode.NotFound):
                    return new InvalidOperationException("The resource requested does not exist.");

                case (HttpStatusCode.Forbidden):
                    {
                        if (msg.Content.ReadAsStringAsync().Result.Contains("AccessDenied"))
                        {
                            return new SecurityException(@"Access Denied. Please check the ACL\Policy settings for the requested resource. Ensure that you have the proper rights to the operation requested.");
                        }
                        else
                        {
                            return new InvalidOperationException("Signature verification has failed..");
                        }
                    }
                default:
                    return new Exception(msg.Content.ReadAsStringAsync().Result);
            }
        }
//=================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="httpStatusCode"></param>
/// <returns></returns>
//=================================================================================================
        public static Exception CreateStorageContainerRepositoryException(HttpResponseMessage msg)
        {
            msg.Content.LoadIntoBufferAsync();
            switch (msg.StatusCode)
            {
                case (HttpStatusCode.NotFound):

                    return new InvalidOperationException("The supplied resource name does not exist.");

                case (HttpStatusCode.Conflict):

                    if (msg.Content.ReadAsStringAsync().Result.Contains("delete"))
                    {
                        return new InvalidOperationException("The storageContainer that you tried to delete is not empty.");
                    }
                    else if (msg.Content.ReadAsStringAsync().Result.Contains("storageContainerAlreadyOwnedByYou"))
                    {
                        return new InvalidOperationException("This storageContainer already exist and is owned by you.");
                    }
                    else if (msg.Content.ReadAsStringAsync().Result.Contains("The requested storageContainer name is not available."))
                    {
                        return new InvalidOperationException("The requested storageContainer name is not available.");
                    }
                    break;

                default:
                    return new Exception(msg.Content.ReadAsStringAsync().Result);
            }
            return new Exception(msg.Content.ReadAsStringAsync().Result);
        }
//=================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
//=================================================================================================
        private static Exception CreateNetworkingException(HttpResponseMessage msg)
        {
            msg.Content.LoadIntoBufferAsync();
            switch (msg.StatusCode)
            {
                case (HttpStatusCode.NotFound):

                    return new InvalidOperationException("The supplied IP Address does not exist.");

                default:
                    return new Exception(msg.Content.ReadAsStringAsync().Result);
            }
        }
//=================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
//=================================================================================================
        private static Exception CreateVolumeException(HttpResponseMessage msg, StackFrame frame)
        {
            msg.Content.LoadIntoBufferAsync();

            switch (frame.GetMethod().Name)
            {
                case ("HPCloud.Objects.DataAccess.BlockStorage.IVolumeRepository.DeleteVolume"):

                    return new InvalidOperationException("Please detach the volume prior to deleting.");

                default:
                    return new Exception(msg.Content.ReadAsStringAsync().Result);
            }
        } 
//=================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="httpStatusCode"></param>
/// <param name="apiType"></param>
/// <returns></returns>
//=================================================================================================
        public static Exception CreateException(HttpResponseMessage msg)
        {
            StackTrace stack = new StackTrace(false);
            msg.Content.LoadIntoBufferAsync();

            StackFrame frame = stack.GetFrame(2);

            switch (frame.GetMethod().ReflectedType.FullName)
            {
                case ("HPCloud.Objects.DataAccess.BlockStorage.VolumeRepository"):
                    return CreateVolumeException(msg, frame);

                case ("HPCloud.Objects.DataAccess.Compute.NetworkRepository"):
                    return CreateNetworkingException(msg);

                case ("HPCloud.Objects.DataAccess.Compute.ServerRepository"):
                    return CreateServerRepositoryException(msg);            

                case ("HPCloud.DataAccess.UserManagement.GroupRepository"):
                    return CreateUserManagementException(msg);

                case ("HPCloud.DataAccess.UserManagement.Tenant"):
                    return CreateUserManagementException(msg);

                case ("HPCloud.Objects.DataAccess.OpenStack.ObjectRepository"):
                    return CreateStorageObjectRepositoryException(msg);

                case ("HPCloud.Objects.DataAccess.OpenStack.ContainerRepository"):
                    return CreateStorageContainerRepositoryException(msg);

                case ("KVMRepository"):

                default:
                    return new Exception(msg.Content.ReadAsStringAsync().Result);
            }
        }

      
    }
}
